<?php
declare (strict_types = 1);

namespace app\middleware;

use app\common\exception\ApiException;
use utils\Ip;

/**
 * 接口数据签名效验 中间件
 * Class webLog
 * @package app\middleware
 */
class ApiHashSalt
{
    /**
     * 前端js配套加密规则
     * @param params 需要加密的参数
     * @param salt  加密的密钥 通常可用用户的身份凭证代替
    const getHash = (params,salt)=>{
    let paramsStrSort = (paramsStr,number)=>{
    paramsStr = encodeURI(paramsStr).replace(',','%2C').replace(/:/g,'%3A').replace(/\//g,'%2F');
    let url = paramsStr.split('&')
    let urlStr = url.sort((a,b)=>{return a-b}).join('&')
    let newUrl = urlStr+'&privateKey='+salt
    //签名并大写
    if(process.env.NODE_ENV=='development'){
    console.log('[sign]',number,newUrl, md5(newUrl).toUpperCase(),md5(newUrl).toUpperCase().substring(number+1,number+18))
    }
    return md5(newUrl).toUpperCase().substring(++number,number+16)
    }
    let number = 0
    if(typeof params == 'string'){
    return paramsStrSort(params,params.length)
    }else if(typeof params == 'object'){
    let arr = []
    for(let i in params){
    if(typeof params[i] == 'object'){
    let key = ''
    for(let j in params[i]){
    if(typeof params[i][j] =='object'){
    for(let o in params[i][j]){
    if(isUndefined(params[i][j][o])) continue;
    key = `${i}[${j}][${o}]=${params[i][j][o]}`;
    arr.push(key)
    }
    }else{
    if(isUndefined(params[i][j])) continue;
    key = `${i}[${j}]=${params[i][j]}`;
    arr.push(key)
    }
    }
    }else{
    if(isUndefined(params[i])) continue;
    arr.push((i+'='+params[i]))
    }
    number++;
    }
    return paramsStrSort(arr.join('&'),number)
    }
    }
     */

    /**
     * 处理请求
     *
     * @param \think\Request $request
     * @param \Closure       $next
     * @return Response
     */
    public function handle($request, \Closure $next)
    {
        //数据签名效验
        $this->checkHashSalt($request);
        return $next($request);
    }

    //参数效验
    public function checkHashSalt($request){
        if($request->isPost()){
            $strkey = '_';
            $PrivateKey = $request->header('Token');
            $postData = $request->post();
            if(empty($postData['t'])){
                throw new ApiException('签名效验失败，参数缺少',101);
            }
            if($postData['t'] < (time().'000')-5000){
                throw new ApiException('签名效验失败，参数有误',101);
            }
            $hashSalt = $postData[$strkey];
            unset($postData[$strkey]);
            foreach ($postData as $k=>$item){
                if(is_array($item)){
                    foreach ($item as $k2=>$v2){
                        if(is_array($v2)){
//                            ksort($postData[$k][$k2],SORT_NATURAL);
                            $this->myKsort($postData[$k][$k2]);
                        }
                    }
//                    ksort($postData[$k],SORT_NATURAL);
                    $this->myKsort($postData[$k]);

                }
            }
//            ksort($postData,SORT_NATURAL);
            $this->myKsort($postData);

            $postData['privateKey'] = $PrivateKey;
            $left = count($postData);
//            dump(http_build_query($postData,'','&'));
//            dump(md5(http_build_query($postData,'','&')));
//            exit;
            $md5 = strtoupper(md5(http_build_query($postData,'','&')));
            $md5 = substr($md5,$left,16);
            if($md5 != $hashSalt){
                $data = [
                    'str'=>http_build_query($postData,'','&'),
                    'md5'=>md5(http_build_query($postData,'','&')),
                    'left'=>$left,
                ];
//                dump($data);exit;
                throw new ApiException('签名效验失败，参数错误',101);
            }
        }
    }

    public function myKsort(&$arr){
        ksort($arr,1);
    }
}
